#ifndef DBSTORAGE_REQUIREMENTS_DB_STORAGE_HPP
#define DBSTORAGE_REQUIREMENTS_DB_STORAGE_HPP

#include "DbStorage/DbStorageBase.hpp"
#include "Storage/RequirementsStorage.hpp"
#include <boost/tuple/tuple.hpp>
#include <map>

namespace CaseDB { class RecordSet; }
namespace Model { class Requirement; }

namespace DbStorage
{

/// @ingroup DbStorage
/// @brief It implements the storage for requirements using database.
class RequirementsDbStorage: public Storage::RequirementsStorage, public DbStorageBase
{
public:
	/// @brief It initializes the storage.
	/// @param factory the storage factory to be used for accessing other dependent storages when needed.
	/// @param pConnection the database connection to be used for storages.
	RequirementsDbStorage( Storage::StorageFactory& factory, CaseDB::Connection* pConnection);
	
	/// @brief It loads the requirements for the specified project.
	/// @param prjToLoad the project that is under loading.
	///
	/// It bulk loads all the requirements related to the given project, then iterates through each project package and 
	///	creates the requirement hierarchies under the appropriate packages.
	virtual void loadRequirements( Model::Project& prjToLoad);

private:
	/// @brief It temporarily stores the information about a requirement, as loaded from the database.
	///
	/// The structure is [PK_REQUIREMENT, FK_PARENT_PACKAGE, POSITION, NAME, STATEMENT].
	typedef boost::tuples::tuple< int, int, int, std::string, std::string> RequirementRecord;

	/// @brief It temporarily stores the raw information about the requirements
	/// 
	/// The key is FK_PARENT_REQUIREMENT.
	typedef std::multimap< int, RequirementRecord> RequirementRawData;

private:
	/// @internal
	/// @brief It gets the data from the record set, converts it to specific types and organizes it for quicker 
	///		requirement hierarchy construction.
	/// @param results the recordset resulted from the database query.
	/// @param rawData the collection where the processed recordset should be stored.
	void makeRawData( const CaseDB::RecordSet& results, RequirementRawData& rawData);

	/// @internal
	/// @brief It processes the raw data, creating the requirements and adding them to the specified project, under the 
	///		appropriate packages.
	/// @param prjToLoad the project to be loaded.
	/// @param rawData the raw data to be processed.
	void processRawData( Model::Project& prjToLoad, const RequirementRawData& rawData);

	/// @internal
	/// @brief It creates the child requirements for the given one, using the provided raw data.
	/// @param pCurRq the requirement to add children to.
	/// @param rawData the data loaded from database.
	void processChildRequirement( Model::Requirement* pCurRq, const RequirementRawData& rawData);
};


} // namespace DbStorage

#endif // DBSTORAGE_REQUIREMENTS_DB_STORAGE_HPP